package com.graduation.smartparkingplatform.Utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;

/** 二维码生成工具类 */
public class QRCodeUtil {
  private static final String CHARSET = "utf-8";
  public static final String FORMAT = "PNG";
  // 二维码尺寸
  private static final int QRCODE_SIZE = 300;
  // LOGO宽度
  private static final int LOGO_WIDTH = 60;
  // LOGO高度
  private static final int LOGO_HEIGHT = 60;
  // Base64字段
  private static final String BASE64_IMAGE = "data:image/png;base64,";

  /**
   * 生成二维码
   *
   * @param content 二维码内容
   * @param logoPath logo地址
   * @param needCompress 是否压缩logo
   * @return 图片
   * @throws Exception
   */
  public static BufferedImage createImage(String content, String logoPath, boolean needCompress)
      throws Exception {
    Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
    hints.put(EncodeHintType.MARGIN, 1);
    BitMatrix bitMatrix =
        new MultiFormatWriter()
            .encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
    int width = bitMatrix.getWidth();
    int height = bitMatrix.getHeight();
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
      }
    }
    if (logoPath == null || "".equals(logoPath)) {
      return image;
    }
    // 插入图片
    QRCodeUtil.insertImage(image, logoPath, needCompress);
    return image;
  }

  /**
   * 插入LOGO
   *
   * @param source 二维码图片
   * @param logoPath LOGO图片地址
   * @param needCompress 是否压缩
   * @throws IOException
   */
  private static void insertImage(BufferedImage source, String logoPath, boolean needCompress)
      throws IOException {
    InputStream inputStream = null;
    try {
      inputStream = QRCodeUtil.getResourceAsStream(logoPath);
      Image src = ImageIO.read(inputStream);
      int width = src.getWidth(null);
      int height = src.getHeight(null);
      if (needCompress) { // 压缩LOGO
        if (width > LOGO_WIDTH) {
          width = LOGO_WIDTH;
        }
        if (height > LOGO_HEIGHT) {
          height = LOGO_HEIGHT;
        }
        Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.drawImage(image, 0, 0, null); // 绘制缩小后的图
        g.dispose();
        src = image;
      }
      // 插入LOGO
      Graphics2D graph = source.createGraphics();
      int x = (QRCODE_SIZE - width) / 2;
      int y = (QRCODE_SIZE - height) / 2;
      graph.drawImage(src, x, y, width, height, null);
      Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
      graph.setStroke(new BasicStroke(3f));
      graph.draw(shape);
      graph.dispose();
    } catch (IOException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    } finally {
      if (inputStream != null) {
        inputStream.close();
      }
    }
  }

  /**
   * 生成二维码(内嵌LOGO)
   *
   * @param content 内容
   * @param logoPath LOGO地址
   * @param output 输出流
   * @param needCompress 是否压缩LOGO
   * @throws Exception
   */
  public static void encode(
      String content, String logoPath, OutputStream output, boolean needCompress) throws Exception {
    BufferedImage image = QRCodeUtil.createImage(content, logoPath, needCompress);
    ImageIO.write(image, FORMAT, output);
  }

  /**
   * 获取指定文件的输入流，获取logo
   *
   * @param logoPath 文件的路径
   * @return
   */
  public static InputStream getResourceAsStream(String logoPath) {
    return QRCodeUtil.class.getResourceAsStream(logoPath);
  }

  public static String getBase64Image(String content, String logoPath, boolean needCompress)
      throws Exception {
    ByteArrayOutputStream bs = new ByteArrayOutputStream(); // io流
    BufferedImage bufferedImage = createImage(content, logoPath, needCompress);
    try {
      ImageIO.write(bufferedImage, "png", bs); // 写入流中
      byte[] bytes = bs.toByteArray(); // 转换成字节
      BASE64Encoder encoder = new BASE64Encoder();
      String png_base64 = encoder.encodeBuffer(bytes).trim(); // 转换成base64串
      png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", ""); // 删除 \r\n
      return BASE64_IMAGE + png_base64;
    } catch (IOException e) {
      System.out.println("生成二维码错误");
    }
    return null;
  }
}
